/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package bluetooth;

import entity.ExampleObject;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Vector;
import javax.bluetooth.DeviceClass;
import javax.bluetooth.DiscoveryAgent;
import javax.bluetooth.DiscoveryListener;
import javax.bluetooth.LocalDevice;
import javax.bluetooth.RemoteDevice;
import javax.bluetooth.ServiceRecord;
import javax.bluetooth.UUID;
import javax.microedition.io.Connector;

import javax.obex.ClientSession;
import javax.obex.HeaderSet;
import javax.obex.Operation;
import javax.obex.ResponseCodes;
import visual.MidletVisual;

/**
 *
 * @author Developer
 */
public class BTObjectClient implements DiscoveryListener, Runnable {

    private static final UUID OBJECT_EXCHANGER_UUID = new UUID("262242B3DADB9A41DE94C7C71CC3AB54", false);
    public static final int BLUETOOTH_TIMEOUT = 30000;
    private Vector btDevicesFound;
    private Vector btServicesFound;
    private boolean isBTSearchComplete;
    private boolean isTerminated = false;
    private ClientSession session;
    private MidletVisual parent;

    public BTObjectClient(MidletVisual parent) {
        this.parent = parent;
        btDevicesFound = new Vector();
        btServicesFound = new Vector();
    }

    /**
     * Finds bluetooth devices
     *
     * @param aServices,
     *          an array with the service UUID identifiers you want to search
     * @returns the number of devices found
     */
    public void run() {
        // while () {
        findDevices();
        if (btDevicesFound.size() > 0) {
            findServices();
        }
        //}
    }

    private void findDevices() {
        try {
            parent.printToFrm("Buscando Dispositivos");
            // cleans previous elements
            btDevicesFound.removeAllElements();
            isBTSearchComplete = false;
            LocalDevice local = LocalDevice.getLocalDevice();
            System.out.println(local.getBluetoothAddress());
            DiscoveryAgent discoveryAgent = local.getDiscoveryAgent();
            // discover new devices
            discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
            System.out.println("Buscando dispositivos...");
            while ((!isBTSearchComplete)) {
                // waits for a fixed time, to avoid long search
                synchronized (this) {
                    this.wait(BLUETOOTH_TIMEOUT);
                }
                // check if search is completed
                if (!isBTSearchComplete || isTerminated) {
                    // search no yet completed so let's cancel it
                    discoveryAgent.cancelInquiry(this);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void deviceDiscovered(RemoteDevice remoteDevice, DeviceClass deviceClass) {
        //if (!banco.buscaEnd(remoteDevice)) { //se não há registro no banco...
        parent.printToFrm("Dispositivo encontrado: " + remoteDevice.getBluetoothAddress());
        btDevicesFound.addElement(remoteDevice);
        System.out.println(remoteDevice.getBluetoothAddress());
        //showAlert("Disp Encontrado");

    }

    public void inquiryCompleted(int param) {
        //showAlert("Busca Disp. finalizada");
        isBTSearchComplete = true;
        // notifies and wake main thread that device search is completed
        synchronized (this) {
            this.notify();
        }
    }

    private void findServices() {
        parent.printToFrm("Buscando Servicos");
        UUID[] uuid = {OBJECT_EXCHANGER_UUID};
        // cleans previous elements
        btServicesFound.removeAllElements();
        try {
            LocalDevice local = LocalDevice.getLocalDevice();
            DiscoveryAgent discoveryAgent = local.getDiscoveryAgent();
            // discover services

            for (int i = 0; i < btDevicesFound.size(); i++) {
                isBTSearchComplete = false;
                RemoteDevice device = (RemoteDevice) btDevicesFound.elementAt(i);
                System.out.println("Buscando serviços... " + device.getFriendlyName(true));;
                int transID = discoveryAgent.searchServices(null, uuid, (RemoteDevice) (btDevicesFound.elementAt(i)), this);

                // wait for service discovery ends
                synchronized (this) {
                    this.wait(BLUETOOTH_TIMEOUT);
                }
                if (!isBTSearchComplete || isTerminated) {
                    discoveryAgent.cancelServiceSearch(transID);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void servicesDiscovered(int param, ServiceRecord[] serviceRecord) {
        btServicesFound.addElement(serviceRecord[0]);
        parent.printToFrm("Serviço econtrado");
    }

    public void serviceSearchCompleted(int transID, int respCode) {
        isBTSearchComplete = true;
        // notifies and wake mains thread that service search is completed
        synchronized (this) {
            this.notify();
        }
        if (btServicesFound.size() > 0) {
            processServices();
        }
    }

    private void processServices() {
        for (int i = 0; i < btServicesFound.size(); i++) {
            ServiceRecord servico = (ServiceRecord) btServicesFound.elementAt(i);
            try {
                parent.printToFrm("Conectando ao servidor: " + servico.getHostDevice().getBluetoothAddress());
                session = (ClientSession) Connector.open(servico.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false));
                
                HeaderSet headerSet = session.connect(null);
                if (headerSet.getResponseCode() == ResponseCodes.OBEX_HTTP_OK) {
                    parent.printToFrm("Conectado! Obtendo Objeto...");
                    ExampleObject objeto = obterObjeto();
                    parent.printToFrm(objeto.toString());
                }
            } catch (IOException ex) {
                parent.printToFrm(ex.toString());
            }
        }
    }

    private ExampleObject obterObjeto() throws IOException {
            //header creating for GET request
            HeaderSet head = session.createHeaderSet();           
            // Set the type of the object to retrieve
            head.setHeader(HeaderSet.NAME, "ExampleObject");
            //head.setHeader(HeaderSet.LENGTH, new Long(0));            


            Operation operation;
            //creating new Operation object for current connection
            operation = session.get(head);
            parent.printToFrm("Solicitada operação GET");
            // getting header...
            HeaderSet getHeader = operation.getReceivedHeaders();

            //Long stringLength = (Long) getHeader.getHeader(HeaderSet.LENGTH);
            String descriptor = (String) getHeader.getHeader(HeaderSet.DESCRIPTION);
            //creating string object
            parent.printToFrm("Lendo bytes..." + descriptor);
            byte[] bytes = new byte[(int)operation.getLength()];
            DataInputStream in = operation.openDataInputStream();
            in.read(bytes);

            ExampleObject object = ExampleObject.getObject(descriptor, bytes);

            //closing input stream
            in.close();
            //closing current operation
            operation.close();
            return object;



            //TODO: write handler code       

    }
}
